package dao

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"go_gateway/common/lib"
	"go_gateway/dto"
	"go_gateway/middleware"
	"go_gateway/public"
	"net/http/httptest"
	"strings"
	"sync"
)

type ServiceDetail struct {
	Info          *ServiceInfo   `json:"info" description:"基本信息"`
	HTTPRule      *HttpRule      `json:"http_rule" description:"http_rule"`
	TCPRule       *TcpRule       `json:"tcp_rule" description:"tcp_rule"`
	GRPCRule      *GrpcRule      `json:"grpc_rule" description:"grpc_rule"`
	LoadBalance   *LoadBalance   `json:"load_balance" description:"load_balance"`
	AccessControl *AccessControl `json:"access_control" description:"access_control"`
}

var ServiceManagerHandler *ServiceManager

func init() {
	ServiceManagerHandler = NewServiceManager()
}

type ServiceManager struct {
	ServiceMap   map[string]*ServiceDetail
	ServiceSlice []*ServiceDetail
	Locker       sync.Mutex
	init         sync.Once
	err          error
}

func NewServiceManager() *ServiceManager {
	return &ServiceManager{ServiceMap: make(map[string]*ServiceDetail), ServiceSlice: []*ServiceDetail{}, Locker: sync.Mutex{}, init: sync.Once{}}
}

// LoadOnce
// @Description: 初始化时加载服务信息
// @receiver serviceManager
// @return error
//
func (s *ServiceManager) LoadOnce() error {
	s.init.Do(func() {
		c, _ := gin.CreateTestContext(httptest.NewRecorder())
		db, err := lib.GetGormPool("default")
		if err != nil {
			s.err = err
			middleware.ResponseError(c, 2001, err)
			return
		}
		// 分页读取信息
		serviceInfo := &ServiceInfo{}
		param := &dto.ServiceListInput{
			PageNo:   1,
			PageSize: 99999,
		}
		list, _, err := serviceInfo.PageList(c, db, param)
		if err != nil {
			s.err = err
		}
		s.Locker.Lock()
		defer s.Locker.Unlock()
		for _, item := range list {
			tempItem := item
			serviceDetail, err := tempItem.ServiceDetail(c, db, &tempItem)
			if err != nil {
				s.err = err
				return
			}
			s.ServiceMap[tempItem.ServiceName] = serviceDetail
			s.ServiceSlice = append(s.ServiceSlice, serviceDetail)
		}
	})
	return s.err
}

// HTTPAccessMode
// @Description: HTTP接入模式
// @receiver s
// @param c
// @return *ServiceDetail
// @return error
//
func (s *ServiceManager) HTTPAccessMode(c *gin.Context) (*ServiceDetail, error) {
	// 1.获取host主机
	host := c.Request.Host
	host = host[0:strings.Index(host, ":")]
	fmt.Println("host: ", host)

	path := c.Request.URL.Path
	for _, serviceItem := range s.ServiceSlice {
		// 判断接入类型是否时HTTP 不是则跳过
		if serviceItem.Info.LoadType != public.LoadTypeHTTP {
			continue
		}
		// 域名匹配
		if serviceItem.HTTPRule.RuleType == public.HTTPRuleTypeDomain {
			if serviceItem.HTTPRule.Rule == host {
				return serviceItem, nil
			}
		}
		// 前缀匹配
		if serviceItem.HTTPRule.RuleType == public.HTTPRuleTypePrefixURL {
			if strings.HasPrefix(path, serviceItem.HTTPRule.Rule) {
				return serviceItem, nil
			}
		}
	}
	return nil, errors.New("not matched service")
}
